package com.ph.shopping.facade.customfactory;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.util.ClassUtils;

import com.ph.shopping.common.core.exception.BizException;
import com.ph.shopping.common.util.container.ClassOperateUtil;
import com.ph.shopping.common.util.container.ContainerUtil;
import com.ph.shopping.common.util.container.ParamVerifyUtil;
import com.ph.shopping.facade.customfactory.facade.ICustomBeanFactory;

public final class CustomBeanImpl implements ICustomBeanFactory<CustomBeanRule>{

	private static BeanService beanService;
	
	/**
	 * bean to bean
	 */
	@Override
	public <T> T generateAppointBean(CustomBeanRule customBean, Class<T> clas) throws Exception {
		T t = null;
		if (customBean == null || clas == null) {
			return t;
		}
		if (beanService == null) {
			beanService = new BeanService();
		}
		Map<String, String> filedMapping = customBean.getFiledMapping();
		if (ParamVerifyUtil.objIsNotNull(filedMapping)) {
			filedMapping = beanService.handleTargetMap(filedMapping, clas, customBean.getNativeProject());
			Map<String, Object> values = beanService.getValueBynative(filedMapping, customBean.getNativeProject());
			if (ParamVerifyUtil.objIsNotNull(values)) {
				t = beanService.getTByValue(customBean, clas, filedMapping, values);
			}
		}
		Map<String, Object> targetProjectValue = customBean.getTargetProjectValue();
		if (ParamVerifyUtil.objIsNotNull(targetProjectValue)) {
			if (t == null) {
				t = clas.newInstance();
			}
			t = beanService.setAppointValue(t, targetProjectValue);
		}
		return t;
	}
	/**
	 * bean to map
	 */
	@Override
	public Map<String, Object> beanToMap(Object obj) throws Exception {
		Map<String, Object> map = ContainerUtil.map();
		if (obj != null) {
			String[] fields = ClassOperateUtil.getFiledStrByClassBySuper(obj.getClass());
			if (fields != null) {
				for (String field : fields) {
					Object value = ClassOperateUtil.getPropertiesValue(field, obj);
					map.put(field, value);
				}
			}
		}
		return map;
	}
	/**
	 * 
	* @ClassName: BeanService  
	* @Description: bean 相关的转换服务  
	* @author lijie  
	* @date 2017年3月19日  
	*
	 */
	protected class BeanService {
		
		/**
		 * 
		* @Title: getTByValue  
		* @Description: 根据取出来的值得到结果  
		* @param @param customBean
		* @param @param clas
		* @param @param filedMapping
		* @param @param values
		* @param @return
		* @param @throws InstantiationException
		* @param @throws IllegalAccessException    参数  
		* @return T    返回类型  
		* @throws
		 */
		public <T> T getTByValue(CustomBeanRule customBean, Class<T> clas, Map<String, String> filedMapping,
				Map<String, Object> values) throws InstantiationException, IllegalAccessException {

			String[] noAssignmentFields = customBean.getNoAssignmentFields();
			if (noAssignmentFields != null && noAssignmentFields.length > 0) {
				values = removeValueByNoass(values, noAssignmentFields);
			}
			if (!values.isEmpty()) {
				String[] targetFields = ClassOperateUtil.getFiledStrByClassBySuper(clas);
				targetFields = new String[targetFields.length];
				targetFields = filedMapping.keySet().toArray(targetFields);
				return getTResult(values, clas, targetFields);
			}
			return null;
		}
		/**
		 * @throws Exception 
		 * 
		* @Title: handleTargetMap  
		* @Description: 过滤不在目标对象里面的字段 
		* @param @param filedMapping
		* @param @param clas
		* @param @return    参数  
		* @return Map<String,String>    返回类型  
		* @throws
		 */
		public Map<String, String> handleTargetMap(Map<String, String> filedMapping, Class<?> clas, Object obj)
				throws Exception {
			if (filedMapping != null && !filedMapping.isEmpty()) {
				String[] tagertFields = ClassOperateUtil.getFiledStrByClassBySuper(clas);
				String[] ve = ClassOperateUtil.getFiledStrByClassBySuper(obj.getClass());
				Iterator<Entry<String, String>> itor = filedMapping.entrySet().iterator();
				while (itor.hasNext()) {
					Entry<String, String> entry = itor.next();
					if (!keyIsExistsByArray(entry.getKey(), tagertFields)) {
						itor.remove();
					} else if (!keyIsExistsByArray(entry.getValue(), ve)) {
						itor.remove();
					} else if (!judgeType(entry.getKey(), entry.getValue(), clas, obj.getClass())) {
						itor.remove();
					}
				}

			}
			return filedMapping;
		}
		/**
		 * @throws IntrospectionException 
		 * 
		* @Title: judgeType  
		* @Description: 判断转换的两则值类型是否相同  
		* @param @param key
		* @param @param targetClas 
		* @param @param nativeClas
		* @param @return    参数  
		* @return boolean    返回类型  
		* @throws
		 */
		private boolean judgeType(String targetKey, String nativeKey, Class<?> targetClas, Class<?> nativeClas)
				throws Exception {
			if (!ClassOperateUtil.isFieldsExistsMethod(targetClas.getMethods(), 
					targetKey, "set")) {
				return false;
			} else if (!ClassOperateUtil.isReadMethod(nativeClas, nativeKey)) {
				return false;
			}
			Method readMethod = createPropertyDescriptor(nativeKey, nativeClas).getReadMethod();
			Method writeMethod = createPropertyDescriptor(targetKey, targetClas).getWriteMethod();
			return ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType());
		}
		/**
		 * 
		 * @Title: createPropertyDescriptor   
		 * @Description: TODO(这里用一句话描述这个方法的作用)   
		 * @param: @param key
		 * @param: @param clas
		 * @param: @return
		 * @param: @throws IntrospectionException      
		 * @return: PropertyDescriptor      
		 * @throws
		 */
		private PropertyDescriptor createPropertyDescriptor(String key,Class<?> clas) throws IntrospectionException{
			
			return new PropertyDescriptor(key,clas);
		}
		/**
		 * 
		* @Title: keyIsExistsByArray  
		* @Description:判断字段是否存在数组中 
		* @param @param key
		* @param @param tagertFields
		* @param @return    参数  
		* @return boolean    返回类型  
		* @throws
		 */
		private boolean keyIsExistsByArray(String key, String[] tagertFields) {
			for (String str : tagertFields) {
				if (str.equals(key)) {
					return true;
				}
			}
			return false;
		}
		/**
		 * 
		* @Title: removeValueByNoass  
		* @Description: 过滤不需要赋值的数据  
		* @param @return    参数  
		* @return Map<String,Object>    返回类型  
		* @throws
		 */
		private Map<String, Object> removeValueByNoass(Map<String, Object> values, String[] noAssignmentFields) {
			if (noAssignmentFields != null && noAssignmentFields.length > 0) {
				for (String key : noAssignmentFields) {
					Object obj = values.get(key);
					if (obj != null) {
						values.remove(key);
					}
				}
			}
			return values;
		}
		/**
		 * 
		* @Title: getValueBynative  
		* @Description: 根据原生的指定字段将值取出来  
		* @param @param keyValue
		* @param @param obj
		* @param @return    参数  
		* @return Map<String,Object>    返回类型  
		* @throws
		 */
		public Map<String, Object> getValueBynative(Map<String, String> keyValue, Object obj) {
			Map<String, Object> map = ContainerUtil.map();
			if (keyValue != null && !keyValue.isEmpty()) {
				for (Map.Entry<String, String> kv : keyValue.entrySet()) {
					if (kv == null)
						continue;
					Object objValue = ClassOperateUtil.getPropertiesValue(kv.getValue(), obj);
					map.put(kv.getKey(), objValue);
				}
			}
			return map;
		}
		/**
		 * 
		* @Title: getTResult  
		* @Description: 赋值操作  
		* @param @param values
		* @param @param clas
		* @param @param targetFields
		* @param @return
		* @param @throws InstantiationException
		* @param @throws IllegalAccessException    参数  
		* @return T    返回类型  
		* @throws
		 */
		private <T> T getTResult(Map<String, Object> values, Class<T> clas, String[] targetFields)
				throws InstantiationException, IllegalAccessException {
			T t = clas.newInstance();
			for (String key : targetFields) {
				if (key == null)
					continue;
				Object objValue = values.get(key);
				ClassOperateUtil.setPropertiesValue(key, t, objValue);
			}
			return t;
		}
		/**
		 * 
		* @Title: setAppointValue  
		* @Description: 赋值指定字段的值  
		* @param @param t
		* @param @param targetProjectValue
		* @param @return    参数  
		* @return T    返回类型  
		* @throws
		 */
		public <T> T setAppointValue(T t, Map<String, Object> targetProjectValue) {
			for (Map.Entry<String, Object> obj : targetProjectValue.entrySet()) {
				if (obj == null)
					continue;
				ClassOperateUtil.setPropertiesValue(obj.getKey(), t, obj.getValue());
			}
			return t;
		}
	}

	/**
	 * 
	* @Title: getKeyValues  
	* @Description: 将字段字符串 转换成map 格式 {"key:value","key:value"}  
	* @param @param strs
	* @param @return    参数  
	* @return Map<String,String>    返回类型  
	* @throws
	 */
	public static Map<String, String> getKeyValues(String[] strs) {
		Map<String, String> map = null;
		try {
			if (strs != null && strs.length > 0) {
				map = ContainerUtil.map();
				for (String str : strs) {
					if (str == null)
						continue;

					String[] kv = str.split(":");
					if (kv.length == 2) {
						map.put(kv[0], kv[1]);
					} else if (kv.length == 1) {
						map.put(kv[0], kv[0]);
					}
				}
			}
		} catch (Exception e) {
			throw new BizException("array format {\"key:value\",\"key:value\"} convert error ", e);
		}
		return map;
	}


}
